# !/usr/bin/env python
# -*- coding: utf-8 -*-
import logging

import redis
from pymongo import MongoClient
from sqlalchemy import MetaData
from sqlalchemy import Table
from sqlalchemy import create_engine, event
from sqlalchemy.exc import DisconnectionError
from sqlalchemy.orm import sessionmaker, mapper
from sqlalchemy.pool import QueuePool

from conf import config
from conf.config import MONGODB_DATABASE, MONGODB_CONN_STR
from conf.config import MYSQL_USER, MYSQL_PWD, MYSQL_HOST, MYSQL_PORT, MYSQL_DB

logger = logging.getLogger("wechat")


def checkout_listener(db_con, con_record, con_proxy):
    try:
        try:
            db_con.ping(False)
        except TypeError:
            db_con.ping()
    except db_con.OperationalError as exc:
        logger.error("连接异常")
        if exc.args[0] in (2006, 2013, 2014, 2045, 2055):
            raise DisconnectionError()
        else:
            raise


connect_str = 'mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8' % (
    MYSQL_USER, MYSQL_PWD, MYSQL_HOST, MYSQL_PORT, MYSQL_DB)
db_engine = create_engine(connect_str, pool_size=10, pool_recycle=3600,
                          echo=False, max_overflow=30, poolclass=QueuePool)
# 使用SQLAlchemy 的 PoolListener 监听链接池的可用性
# 在链接被 checkout 使用时，先验证链接的有效性，若无效则抛出 DisconnectionError 错误，让链接池回收，重新创建个新的链接
event.listen(db_engine, 'checkout', checkout_listener)


def get_db_session(mapper_list):
    """
    获取sqlalchemy的session
    :param mapper_list: 例如：[{"db_table":"sdet_goods","model":Goods}]
    :return:
    """

    Session = sessionmaker(bind=db_engine)
    session = Session()

    metadata = MetaData(db_engine)
    for m in mapper_list:
        table = Table(m["db_table"], metadata, autoload=True)
        mapper(m["model"], table)
    return session


class Redis(object):
    def __init__(self):
        redis_connection_pool = redis.ConnectionPool(max_connections=config.REDIS_MAX_CONNECTIONS,
                                                     host=config.REDIS_HOST,
                                                     port=config.REDIS_PORT,
                                                     db=config.REDIS_DB,
                                                     password=config.REDIS_PWD)
        redis_client = redis.Redis(connection_pool=redis_connection_pool)
        self.client = redis_client


# 使用redis连接池
redis_util = Redis()


class MongodbUtil:
    def __init__(self):
        self.conn = self.get_conn()
        self.db = self.get_db()

    def get_conn(self):
        return MongoClient(MONGODB_CONN_STR)

    def get_db(self):
        return self.conn[MONGODB_DATABASE]


mongodb_util = MongodbUtil()
